/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fr.maistre.swarn;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author Louis Maistre
 */
public abstract class Entity extends Thread {

	private static long TIME_OUT = 10;
	private long TIC = 0;

	static long LAST_ID = 0;
	protected long id;

	private long startTime;
	protected long lifeTime;

	protected ListRessources ressources = new ListRessources();
	protected ListRessources ressourcesCritiques = new ListRessources();
	protected Goal goal;
	private long durability;
	protected Environement environement;

	protected DNA DNA;

	public Entity(DNA DNA, Environement environement, Goal goal,
			ListRessources ressourcesCritiques,ListRessources ressources) {
		this(DNA, environement, goal, ressourcesCritiques);
		this.addRessources(ressources);

	}

	public Entity(DNA DNA, Environement environement, Goal goal,
			ListRessources ressourcesCritiques) {
		LAST_ID++;
		this.id = LAST_ID;
		this.durability = this.setLifetime();
		this.setName("Entity: " + this.id);
		this.goal = goal;
		this.DNA = DNA;
		this.environement = environement;
		this.ressourcesCritiques.addAll(ressourcesCritiques);
	}

	@Override
	public synchronized void start() {
		startTime = System.nanoTime();
		System.out.println(this + " I'm Born RCI: " + ressourcesCritiques
				+ " RI: "
				+ this.ressources + "\n");
		super.start();
	}

	@Override
	public void run() {
		super.run();

		do {
			try {
				this.reach(goal);
				this.act(DNA.getRandom());
				this.sleep(TIME_OUT);
				TIC++;
				/*System.out.println(this + " RC: "
						+ ressourcesCritiques.toString() + " R: "
						+ ressources.toString() + " TIC: " + TIC);*/
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			durability--;
		} while (durability > 0 && !ressourcesCritiques.isEmpty());

		die();
	}

	void reach(Goal goal) {
		
		try {
			this.removeRessources(goal.getCost());
			if (goal.isReached()) {
				this.addRessources(goal.getReward());
			}
		} catch (Exception e) {
			// TODO catch exeption via le goal
			// e.printStackTrace();
		}
	}

	abstract protected void act(char random);

	private void die() {
		this.lifeTime = System.nanoTime() - startTime;

		System.out.println(this + "I'm dead durability " + durability
				+ " |RC: " + this.ressourcesCritiques + " R: "
				+ this.ressources + "| lifetime: "
				+ TimeUnit.NANOSECONDS.toMillis(lifeTime) + " ms\n" + DNA);

		this.stop();

	}

	protected void addRessource(Ressource ressourceToAdd) {

		if (ressourcesCritiques.contains(ressourceToAdd)) {
			ressourcesCritiques.add(ressourceToAdd);
		} else {
			ressources.add(ressourceToAdd);
		}
	}
	
	protected void addRessources(ListRessources listRessources){
		for (Ressource ressource : listRessources) {
			this.addRessource(ressource);
		}
	}



	protected void removeRessource(Ressource ressourceToRemove)
			throws Exception {
		if (ressourceToRemove.quantity >= 0) {
			if (this.ressourcesCritiques.contains(ressourceToRemove)) {
				this.ressourcesCritiques.remove(ressourceToRemove);
			} else {
				this.ressources.remove(ressourceToRemove);
			}
		}
	}

	protected void removeRessources(ListRessources ressourcesToRemove)
			throws Exception {
		for (Ressource ressourceToRemove : ressourcesToRemove) {
			this.removeRessource(ressourceToRemove);
		}
	}

	protected void clearAllRessources() {
		ressources.clear();
		ressourcesCritiques.clear();
	}

	abstract protected void alterEnvironement();

	abstract protected void scanEnvironement();

	protected abstract String mutateADN();

	protected boolean haveEnoughtRessources(List<Ressource> ressources) {
		boolean haveEnough = true;
		for (Ressource ressource : ressources) {
			if (!haveEnoughtRessources(ressource)) {
				haveEnough = false;
			}
		}
		return haveEnough;
	}

	protected boolean haveEnoughtRessources(Ressource ressource) {
		if (this.getAllRessources().contains(ressource)) {
			Ressource existingRessource = getAllRessources().get(
					getAllRessources().indexOf(ressource));
			if (existingRessource.quantity >= ressource.quantity) {
				return true;
			}
		}
		return false;
	}

	@Override
	public String toString() {
		return this.getClass().getSimpleName() + "(" + this.id + ")::";
	}

	protected abstract long setLifetime();

	protected List<Ressource> getAllRessources() {
		List<Ressource> allRessources = new ArrayList<Ressource>();
		allRessources.addAll(ressources);
		allRessources.addAll(ressourcesCritiques);
		return allRessources;
	}
}
